淺談 throw 與 throw ex 的差異
TLDR
- 使用
throw;可以保留原始的 Stack Trace,確保除錯時能追蹤到錯誤發生的原始位置。 - 使用
throw ex;會重置 Stack Trace,導致錯誤堆疊資訊遺失,應避免使用。 - 若需拋出新的 Exception,應將原始 Exception 作為
InnerException傳入,以保留錯誤上下文。 - 若
catch區塊內僅執行throw;而無其他邏輯,則應移除該try...catch區塊。 - .NET 5 以上版本提供
CA2200規則,會自動偵測並警告throw ex的不當使用。
throw 與 throw ex 的差異分析
在 C# 的 try...catch 區塊中,throw; 與 throw ex; 的行為有顯著差異。
使用 throw 保留堆疊資訊
什麼情況下會遇到這個問題:當需要在 catch 區塊中攔截例外,進行記錄或處理後,再將原始例外繼續向上拋出時。
使用 throw; 可以重新拋出捕捉到的 Exception,並完整保留原始的 Exception 堆疊資訊。這對於除錯至關重要,因為它能提供正確的錯誤發生路徑。
csharp
try {
try {
int result = Divide(1, 0);
} catch {
throw;
}
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
static int Divide(int numerator, int denominator) {
return numerator / denominator;
}執行結果顯示,錯誤路徑明確指向第 3 行的 Divide 方法:
text
System.DivideByZeroException: Attempted to divide by zero.
at Program.<<Main>$>g__Divide|0_0(Int32 numerator, Int32 denominator) in D:\Programming\Projects\TestThrow\TestThrow\Program.cs:line 12
at Program.<Main>$(String[] args) in D:\Programming\Projects\TestThrow\TestThrow\Program.cs:line 3使用 throw ex 導致堆疊遺失
什麼情況下會遇到這個問題:開發者誤以為 throw ex 是重新拋出例外的一般寫法,卻忽略了它會將例外物件視為一個「新的」錯誤來源。
使用 throw ex 會建立一個新的 Exception 並拋出,這會重置 Exception 的堆疊資訊,使得追蹤變得困難。
csharp
try {
try {
int result = Divide(1, 0);
} catch (Exception ex) {
throw ex;
}
} catch (Exception e) {
Console.WriteLine(e.ToString());
}執行結果顯示,錯誤發生位置變成了 throw ex 所在的行數,原始的錯誤路徑已遺失:
text
System.DivideByZeroException: Attempted to divide by zero.
at Program.<Main>$(String[] args) in D:\Programming\Projects\TestThrow\TestThrow\Program.cs:line 5TIP
測試結果顯示,使用 throw ex 重新拋出的 Exception,其 InnerException 為 null,這證實了原始的堆疊資訊確實會遺失。
最佳實踐與建議
正確封裝 Exception
什麼情況下會遇到這個問題:當需要拋出自定義的 Exception,同時又想保留原始錯誤資訊時。
我們應該拋出一個新的 Exception,並將原始 Exception 作為 innerException 參數傳遞。這樣既能增加新的上下文資訊,又能保留原始的堆疊追蹤。
csharp
public class CustomException : Exception {
public CustomException(string message, Exception innerException)
: base(message, innerException) {
}
}
try {
// 可能發生 Exception 的程式碼...
} catch (Exception ex) {
// ex 要作為 InnerException 傳入,才能保留資訊
throw new CustomException("額外的資訊", ex);
}避免無效的 try...catch
什麼情況下會遇到這個問題:在程式碼中撰寫了 try...catch 區塊,但 catch 內部僅執行 throw; 而未進行任何額外處理。
若 catch 區塊內沒有任何處理邏輯,僅僅是 throw;,則應直接移除該 try...catch 區塊,因為它對程式執行沒有任何正面影響。
csharp
// 建議移除此類無意義的 catch
try {
// 可能發生 Exception 的程式碼...
} catch {
throw;
}異動歷程
- 2025-07-31 初版文件建立。
